#!/usr/bin/env python
#
# Copyright (C) 2011 Clement Lorteau <clem@lorteau.fr>	
#		
# This file is part of QuickScreenShots.		
# 	
# This program is free software; you can redistribute it and/or modify	
# it under the terms of the GNU General Public License as published by		
# the Free Software Foundation; version 3.	
# 	
# This program is distributed in the hope that it will be useful,		
# but WITHOUT ANY WARRANTY; without even the implied warranty of		
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the		
# GNU General Public License for more details.		
# 		
# You should have received a copy of the GNU General Public License		
# along with this program; if not, write to the Free Software		
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.

import wx
import wx.lib.newevent
import platform
import intbutton
import options
import drawing
from options import Options
import webbrowser
from wx.lib.buttons import ThemedGenBitmapTextButton as bbutton
from wx.lib.buttons import ThemedGenBitmapToggleButton as tbutton
from wx.lib.scrolledpanel import ScrolledPanel
from PIL import Image
from __init__ import __version__, resources

"""screenshot events IDs"""
ID_REGION = wx.NewId()
ID_WINDOW = wx.NewId()
ID_DESKTOP = wx.NewId()
"""command events IDs"""
ID_COPY = wx.NewId()
ID_PREFS = wx.ID_PREFERENCES
ID_PRINT = wx.NewId()
ID_SAVE = wx.NewId()
ID_VIEW = wx.NewId()
ID_CLOSE = wx.NewId()
ID_UPDATE = wx.NewId()
ID_QUIT = wx.ID_EXIT
ID_REAPPLY = wx.NewId()
"""GUI internal only IDs"""
ID_ABOUT = wx.ID_ABOUT
ID_HOMEPAGE = wx.NewId()
"""Drawing commands IDs"""
ID_DRAW_RECT = wx.NewId()
ID_DRAW_CIRCLE = wx.NewId()
ID_DRAW_FREE = wx.NewId()
ID_DRAW_LINE = wx.NewId()
ID_DRAW_CLEAR = wx.NewId()
ID_DRAW_ARROW = wx.NewId()
ID_DRAW_BLUR = wx.NewId()

screenshot_event, EVT_SCREENSHOT_EVENT = wx.lib.newevent.NewCommandEvent()
effect_event, EVT_EFFECT_EVENT = wx.lib.newevent.NewCommandEvent()
command_event, EVT_COMMAND_EVENT = wx.lib.newevent.NewCommandEvent()
drawing_event, EVT_DRAWING_EVENT = wx.lib.newevent.NewCommandEvent()

class ScreenshotEvent(screenshot_event):
    """Triggered when the user wants to take a screenshot"""
    def __init__(self, id):
        screenshot_event.__init__(self, id)
        
class CommandEvent(command_event):
    """Triggered when the user wants to copy, print or save the screenshot"""
    def __init__(self, image, params, id):
        self.image = image
        self.params = params
        command_event.__init__(self, id)
        
    def GetParams(self):
        return self.params
        
    def GetImage(self):
        return self.image

class EffectEvent(effect_event):
    """Triggered when the users want to apply an effect to the screenshot"""
    def __init__(self, image, params, id):
        self.image = image
        self.params = params
        effect_event.__init__(self, id)
        
    def GetParams(self):
        return self.params
        
    def GetImage(self):
        return self.image
        
class DrawingEvent(drawing_event):
    """Triggered when a drawing object was added to the screenshot"""
    def __init__(self):
        drawing_event.__init__(self, 0)
   
    def GetEventType(self):
        return self.event_type

class QSSFrame(wx.Frame):
    """The main application frame"""
    def __init__(self, opts, evthdl, *args, **kwds):
        self.options = opts
        self.evthdl = evthdl
        self.im = None
        self.orig_im = None
        self.imtb = None
        self.drawing_mode = False
        self.resizing = False
        self.curTool = None
        self.penColour = self.options.draw_line_color.GetValue()
        self.fillColour = None
        self.lineSize = self.options.draw_line_size.GetValue()
        self.previoussize = (0, 0)
        self.keyMap = {}
        self.gen_keymap()
        self.invertKeyMap = dict([(v, k) for (k, v) in self.keyMap.iteritems()])
        # begin wxGlade: QSSFrame.__init__
        kwds["style"] = wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        self.drawpanel = wx.Panel(self, -1)
        self.panel_1 = wx.Panel(self, -1, style=wx.SIMPLE_BORDER|
                                                wx.TAB_TRAVERSAL)
        
        # Menu Bar
        self.menubar = wx.MenuBar()
        self.filemenu = wx.Menu()
        self.menubar.Append(self.filemenu, "File")
        self.editmenu = wx.Menu()
        self.menubar.Append(self.editmenu, "Edit")
        self.helpmenu = wx.Menu()
        self.homepagemenu = wx.MenuItem(self.helpmenu, ID_HOMEPAGE, "Visit home page", "", wx.ITEM_NORMAL)
        self.helpmenu.AppendItem(self.homepagemenu)
        self.updatemenu = wx.MenuItem(self.helpmenu, ID_UPDATE, "Check for updates", "", wx.ITEM_NORMAL)
        self.helpmenu.AppendItem(self.updatemenu)
        self.helpmenu.AppendSeparator()
        self.aboutmenu = wx.MenuItem(self.helpmenu, ID_ABOUT, "About", "", wx.ITEM_NORMAL)
        self.helpmenu.AppendItem(self.aboutmenu)
        self.menubar.Append(self.helpmenu, "Help")
        self.SetMenuBar(self.menubar)
        # Menu Bar end
        self.previewBitmap = wx.StaticBitmap(self.panel_1, -1, wx.NullBitmap,
                                             style=wx.NO_FULL_REPAINT_ON_RESIZE | wx.CLIP_CHILDREN)
        self.copycheckbox = wx.CheckBox(self, -1, "Auto copy")
        self.savecheckbox = wx.CheckBox(self, -1, "Auto save")
        self.savesettingsbutton = wx.BitmapButton(self, -1, wx.Bitmap("%s/settings_16.png" % resources,
        															  wx.BITMAP_TYPE_ANY))
        self.shadowcheckbox = wx.CheckBox(self, -1, "Shadow")
        self.shadowsettingsbutton = wx.BitmapButton(self, -1, wx.Bitmap("%s/settings_16.png" % resources,
        																wx.BITMAP_TYPE_ANY))
        self.rotatecheckbox = wx.CheckBox(self, -1, "Rotate")
        self.rotatesettingsbutton = wx.BitmapButton(self, -1, wx.Bitmap("%s/settings_16.png" % resources,
        																wx.BITMAP_TYPE_ANY))
        self.monocheckbox = wx.CheckBox(self, -1, "B/W")
        self.label_1 = wx.StaticText(self, -1, "~  Drawing  ~", style=wx.ALIGN_CENTRE)

        self.__set_properties()
        self.__do_layout()
        # end wxGlade
      
      	if platform.system() == 'Windows':
        	self.icon = wx.Icon("%s/snapshot.ico" % resources, wx.BITMAP_TYPE_ICO)
    	elif platform.system() == 'Darwin':
    		self.icon = wx.Icon("%s/snapshot.png" % resources, wx.BITMAP_TYPE_PNG)
        self.SetIcon(self.icon)
        self.__add_custom_widgets()
        self.__register_hotkeys()
        self.ClearIM()
        self.ApplyOptions()
        
        self.recttool = drawing.RectDrawingTool()
        self.circletool = drawing.EllipseDrawingTool()
        self.freetool = drawing.ScribbleDrawingTool()
        self.linetool = drawing.LineDrawingTool()
        self.arrowtool = drawing.ArrowDrawingTool()
        self.blurtool = drawing.BlurDrawingTool()
        drawing.Init() #initialize OGL
        
        self.Bind(wx.EVT_BUTTON, self.onButton)
        self.Bind(wx.EVT_MENU, self.onMenu)
        self.Bind(wx.EVT_CHECKBOX, self.OnCheckbox)
        self.Bind(wx.EVT_CLOSE, self.OnClose)
        self.Bind(wx.EVT_SIZE, self.OnResize)
        self.Bind(wx.EVT_HOTKEY, self.OnDesktopHotkey, id=ID_DESKTOP)
        self.Bind(wx.EVT_HOTKEY, self.OnWindowHotkey, id=ID_WINDOW)
        self.Bind(wx.EVT_HOTKEY, self.OnRegionHotkey, id=ID_REGION)
        self.Bind(wx.EVT_COLOURPICKER_CHANGED, self.OnColorChanged)
        self.Bind(intbutton.EVT_SPIN_BUTTON_CHANGED, self.OnSpinButtonChanged)
        self.Bind(wx.EVT_SIZING, self.OnResizing)
        self.previewBitmap.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouseEvent)
        self.Bind(wx.EVT_PAINT, self.onPaint)
        
        self.wrapDC = lambda dc: wx.GCDC(dc)
        #self.wrapDC = lambda dc: dc
        
        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.OnTimer)
        self.timer.Start(300)
        
        if platform.system() == 'Darwin':
        	self.Fit()
        
    def gen_keymap(self):
        """source: Josiah Carlson - http://come.to/josiah"""
        keys = ("BACK", "TAB", "RETURN", "ESCAPE", "SPACE", "DELETE", "START",
            "LBUTTON", "RBUTTON", "CANCEL", "MBUTTON", "CLEAR", "PAUSE",
            "CAPITAL", "PRIOR", "NEXT", "END", "HOME", "LEFT", "UP", "RIGHT",
            "DOWN", "SELECT", "PRINT", "EXECUTE", "SNAPSHOT", "INSERT", "HELP",
            "NUMPAD0", "NUMPAD1", "NUMPAD2", "NUMPAD3", "NUMPAD4", "NUMPAD5",
            "NUMPAD6", "NUMPAD7", "NUMPAD8", "NUMPAD9", "MULTIPLY", "ADD",
            "SEPARATOR", "SUBTRACT", "DECIMAL", "DIVIDE", "F1", "F2", "F3", "F4",
            "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "F13", "F14",
            "F15", "F16", "F17", "F18", "F19", "F20", "F21", "F22", "F23", "F24",
            "NUMLOCK", "SCROLL", "PAGEUP", "PAGEDOWN", "NUMPAD_SPACE",
            "NUMPAD_TAB", "NUMPAD_ENTER", "NUMPAD_F1", "NUMPAD_F2", "NUMPAD_F3",
            "NUMPAD_F4", "NUMPAD_HOME", "NUMPAD_LEFT", "NUMPAD_UP",
            "NUMPAD_RIGHT", "NUMPAD_DOWN", "NUMPAD_PRIOR", "NUMPAD_PAGEUP",
            "NUMPAD_NEXT", "NUMPAD_PAGEDOWN", "NUMPAD_END", "NUMPAD_BEGIN",
            "NUMPAD_INSERT", "NUMPAD_DELETE", "NUMPAD_EQUAL", "NUMPAD_MULTIPLY",
            "NUMPAD_ADD", "NUMPAD_SEPARATOR", "NUMPAD_SUBTRACT", "NUMPAD_DECIMAL",
            "NUMPAD_DIVIDE")
        
        for i in keys:
            self.keyMap[getattr(wx, "WXK_"+i)] = i
        for i in ("SHIFT", "ALT", "CONTROL", "MENU"):
            self.keyMap[getattr(wx, "WXK_"+i)] = ''
        
    def SetOptions(self, opts):
        self.options = opts
        self.ApplyOptions()
        
    def UpdateThumbnail(self, nolayout=False):
        if self.im:
            wx.Yield()
            if not self.drawing_mode:
                s = self.previewBitmap.GetParent().GetSize()
                self.previewBitmap.SetSize((s[0] - 10, s[1] - 10))
                size = self.previewBitmap.GetSize()
                imtb = self.im.copy()
                imtb.thumbnail(size, Image.ANTIALIAS)
                tbbmp = self.BitmapFromImage(imtb)
                self.previewBitmap.SetBitmap(tbbmp)
                self.previewBitmap.SetSize(size)
                self.imtb = imtb
                self.previewBitmap.GetParent().Refresh()
            if self.drawing_mode:
                self.scrolled.SetDoubleBuffered(True)
                bmp = self.BitmapFromImage(self.im)
                self.previewBitmap.SetBitmap(bmp)
                if not nolayout:
                    w = self.previewBitmap.GetBitmap().GetWidth()
                    h = self.previewBitmap.GetBitmap().GetHeight()
                    self.previewBitmap.SetSize((w, h))
                    #display scrollbars correctly
                    self.scrolled.SetVirtualSize((w, h))
                    self.scrolled.Show()
                    self.Layout()
                # force the bitmap to be in the upper left corner of the scrolled window
                self.previewBitmap.SetClientSize(self.previewBitmap.GetBestSize())
    
    def GetIM(self):
        return self.im
    
    def SetIM(self, im):
        """Set the active screenshot PIL Image"""
        if not im:
            return
        self.im = im
        self.UpdateThumbnail(True)
        
        self.savebutton.Enable(True)
        self.copybutton.Enable(True)
        self.viewbutton.Enable(True)
        self.viewmenu.Enable(True)
        self.savemenu.Enable(True)
        self.copymenu.Enable(True)
        self.drawpanel.Enable(True)
        self.drawclearbutton.Enable(False)
        
    def BitmapFromImage(self, pilImage):
        """source: http://jehiah.cz/a/pil-to-wxbitmap"""
        image = wx.EmptyImage(pilImage.size[0],pilImage.size[1])
        image.SetData(pilImage.convert("RGB").tostring())
        image.SetAlphaData(pilImage.convert("RGBA").tostring()[3::4])
        return wx.BitmapFromImage(image)
        
    def GetOrigIM(self):
        return self.orig_im
        
    def SetOrigIM(self, im):
        self.orig_im = im
        
    def ClearIM(self):
        """Clear the active screenshot image"""
        self.im = None
        self.imtb = None
        self.previewBitmap.SetBitmap(wx.NullBitmap)
        self.savebutton.Enable(False)
        self.copybutton.Enable(False)
        self.viewbutton.Enable(False)
        self.viewmenu.Enable(False)
        self.savemenu.Enable(False)
        self.copymenu.Enable(False)
        self.drawpanel.Enable(False)
        
    def SetDrawingMode(self, value):
    
        if value and not self.drawing_mode: #enter drawing mode
            self.SetDoubleBuffered(True) #prevent flickering

            #replace the un scrollable panel by the scrolledpanel
            self.panel_1.Reparent(self)
            self.panel_1.Hide()
            self.sizer_3.Detach(self.panel_1)
            self.sizer_6.Detach(self.previewBitmap)
            self.previewBitmap.Reparent(self.scrolled)
            self.sizer_3.Prepend(self.scrolled, 1, wx.ALL|wx.EXPAND|wx.ALIGN_LEFT, 5)
            self.sizer_7.Add(self.previewBitmap, 1, wx.ALL|wx.ALIGN_LEFT|wx.ALIGN_TOP, 5)
            
        elif self.drawing_mode: #leave drawing mode
        
            for b in self.drawingtoolsbuttons:
                if b != self.drawclearbutton and b.GetValue():
                    return #don't leave drawing mode if another button, except
                           #the clear button, is pressed
                           
            self.SetDoubleBuffered(True) #prevent flickering

            self.scrolled.Hide()
            #replace the scrolledpanel by the normal panel
            self.scrolled.Scroll(0, 0)
            self.scrolled.Reparent(self)
            self.sizer_3.Detach(self.scrolled)
            self.sizer_3.Prepend(self.panel_1, 1, wx.ALL|wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL, 5)
            self.sizer_7.Detach(self.previewBitmap)
            self.sizer_6.Add(self.previewBitmap, 1, wx.ALL|wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL, 5)
            self.previewBitmap.Reparent(self.panel_1)
            self.panel_1.Show()
            self.Layout()
            
        else:
            return #inconsistent, do nothing
            
        self.drawing_mode = value
        self.UpdateThumbnail()
        self.SetDoubleBuffered(False)
            
    def doprint(self):
        evt_obj = CommandEvent(self.im, None, ID_PRINT)
        self.evthdl.ProcessEvent(evt_obj)
        
    def save(self):
        dir = self.options.save_dir.GetValue()
        wildcard = "JPEG files (*.jpg, *.jpeg)|*.jpg;*.jpeg|All files (*.*)|*.*"
        dialog = wx.FileDialog(self, message='Save screenshot as...',
                               defaultDir=dir,
                               defaultFile='', wildcard=wildcard,
                               style=wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
        if dialog.ShowModal() == wx.ID_OK:
            path = dialog.GetPath()
            evt_obj = CommandEvent(self.im, path, ID_SAVE)
            self.evthdl.ProcessEvent(evt_obj)
        dialog.Destroy()
        
    def about(self):
        description = """QuickScreenShots is meant to make the process of taking screenshots
and using them as painless, quick and efficient as possible."""
        licence = """This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; version 3.
        
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 		
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
St, Fifth Floor, Boston, MA 02110-1301, USA."""
        info = wx.AboutDialogInfo()
        info.SetIcon(self.icon)
        info.SetName('QuickScreenShots')
        info.SetVersion(__version__)
        info.SetDescription(description)
        info.SetCopyright('(C) 2011 Clement Lorteau')
        info.SetWebSite('http://www.lorteau.net/quickscreenshots')
        info.SetLicence(licence)
        wx.AboutBox(info)
        
    def homepage(self):
        webbrowser.open('http://www.lorteau.net/quickscreenshots')
    
    def ApplyOptions(self):
        o = self.options
        self.copycheckbox.SetValue(o.copy_use.GetValue())
        self.savecheckbox.SetValue(o.save_use.GetValue())
        self.shadowcheckbox.SetValue(o.shadow_use.GetValue())
        self.rotatecheckbox.SetValue(o.rotate_use.GetValue())
        self.monocheckbox.SetValue(o.mono_use.GetValue())
        color = o.draw_line_color.GetValue()
        self.drawcolorbutton.SetColour(color)
        self.drawlinesizebutton.SetValue(o.draw_line_size.GetValue())

    def requestRedraw(self):
        #draw on the screenshot widget's DC
        wdc = wx.WindowDC(self.previewBitmap)
        if platform.system() == 'Darwin': #OS X double buffers automatically
            dc = wdc
        else:
            dc = wx.BufferedDC(wdc)
        dc.DrawBitmap(self.previewBitmap.GetBitmap(), 0, 0)
        self.drawContents(dc)
        del dc
        
    def addObject(self, obj, select=True):
        """Called on left mouse button goes up. Commits changes to the
        displayed screenshot by drawing on the bitmap's DC and assigning
        that bitmap to the screenshot widget"""
        
        #prevent flickering
        # self.scrolled.SetDoubleBuffered(True)
        
        #pull the current bitmap from the widget, paint the new bitmap on top of it
        mdc = wx.MemoryDC()
        sbmp = self.previewBitmap.GetBitmap()
        bmp = sbmp.GetSubBitmap(wx.Rect(0, 0, sbmp.GetWidth(), sbmp.GetHeight()))
        mdc.SelectObject(bmp)
        self.drawContents(mdc)
        mdc.SelectObject(wx.NullBitmap)
        
        #commit changes to the stored screenshot and refresh display
        #http://wiki.wxpython.org/WorkingWithImages#Converting_Between_PIL_image.2C_wx.Bitmap_and_wx.Image
        wximage = wx.ImageFromBitmap(bmp)
        pilimage = Image.new( 'RGB', (wximage.GetWidth(), wximage.GetHeight()) )
        pilimage.fromstring(wximage.GetData())
        self.SetIM(pilimage)
        
        self.drawclearbutton.Enable(True)
        #fire an event indicating that a new drawing was done
        event_obj = DrawingEvent()
        self.GetEventHandler().ProcessEvent(event_obj)
        
        
    def drawContents(self, dc):
        """
        Does the actual drawing of all drawing contents with the specified dc
        Also copied from pySketch
        """
        # PrepareDC sets the device origin according to current scrolling
        self.scrolled.PrepareDC(dc)

        gdc = self.wrapDC(dc)

        if self.curTool is not None:
            self.curTool.draw(gdc)
        
    def __register_hotkeys(self):
        """register system wide keyboard shortcuts"""
        for (kb, id) in ((self.options.kb_desktop.GetValue().split('+'), ID_DESKTOP),
                         (self.options.kb_window.GetValue().split('+'), ID_WINDOW),
                         (self.options.kb_region.GetValue().split('+'), ID_REGION)):
            modifiers = 0
            for mod, keyname in ((wx.MOD_CONTROL, 'Ctrl'),
                                 (wx.MOD_ALT, 'Alt'),
                                 (wx.MOD_WIN, 'Win'),
                                 (wx.MOD_SHIFT, 'Shift')):
                if keyname in kb:
                    modifiers = modifiers|mod
                    kb.remove(keyname)
            lastkey = kb[0]
            try:
                lastkeycode = ord(lastkey)
            except TypeError, e:
                lastkeycode = self.invertKeyMap[lastkey]
            self.RegisterHotKey(id, modifiers, lastkeycode) #so easy. I love wxpython :)
    
    def __add_custom_widgets(self):
        self.scrolled = ScrolledPanel(self, -1,
                                      style=wx.SIMPLE_BORDER | wx.TAB_TRAVERSAL | wx.NO_FULL_REPAINT_ON_RESIZE | wx.CLIP_CHILDREN)
        # if not self.scrolled.IsDoubleBuffered():
            # self.scrolled.SetDoubleBuffered(True)
        self.scrolled.SetMinSize((500, 400))
        self.scrolled.SetBackgroundColour(wx.Colour(255, 255, 255))
        self.sizer_7 = wx.BoxSizer(wx.HORIZONTAL)
        self.scrolled.SetSizer(self.sizer_7)
        self.scrolled.SetupScrolling()
        self.scrolled.Hide()
        #bitmap buttons
        font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
        bigfont = wx.Font(font.GetPointSize()+1, font.GetFamily(), font.GetStyle(),
                          font.GetWeight(), font.GetUnderlined(), font.GetFaceName(),
                          font.GetEncoding())
        
        bmpregion = wx.Bitmap("%s/region_20.png" % resources, wx.BITMAP_TYPE_PNG)
        self.regionbutton = bbutton(self, bitmap=bmpregion, style=wx.BU_LEFT,
                                    label='  Region screenshot            ')
        self.regionbutton.SetFont(bigfont)
        self.sizer_4.Prepend(self.regionbutton, 0, wx.ALL|wx.EXPAND, 5)
        
        bmpwindow = wx.Bitmap("%s/window_20.png" % resources, wx.BITMAP_TYPE_PNG)
        self.windowbutton = bbutton(self, bitmap=bmpwindow, style=wx.BU_LEFT,
                                    label='  Active window screenshot ')
        self.windowbutton.SetFont(bigfont)
        self.sizer_4.Prepend(self.windowbutton, 0, wx.ALL|wx.EXPAND, 5)
        
        bmpdesktop = wx.Bitmap("%s/desktop_20.png" % resources, wx.BITMAP_TYPE_PNG)
        self.desktopbutton = bbutton(self, bitmap=bmpdesktop, style=wx.BU_LEFT,
                                     label='  Full desktop screenshot    ')
        self.desktopbutton.SetFont(bigfont)
        self.sizer_4.Prepend(self.desktopbutton, 0, wx.ALL|wx.EXPAND, 5)
        
        bmpsave = wx.Bitmap("%s/save_16.png" % resources, wx.BITMAP_TYPE_PNG)
        self.savebutton = bbutton(self, bitmap=bmpsave, style=wx.BU_LEFT,
                                  label='  Save as')
        self.sizer_1.Add(self.savebutton, 0, wx.ALL|wx.EXPAND, 5)
        
        bmpcopy = wx.Bitmap("%s/copy_16.png" % resources, wx.BITMAP_TYPE_PNG)
        self.copybutton = bbutton(self, bitmap=bmpcopy, style=wx.BU_LEFT,
                                  label='  Copy')
        self.sizer_1.Add(self.copybutton, 0, wx.ALL|wx.EXPAND, 5)
        
        bmpview = wx.Bitmap("%s/view_16.png" % resources, wx.BITMAP_TYPE_PNG)
        self.viewbutton = bbutton(self, bitmap=bmpview, style=wx.BU_LEFT,
                                  label='  View')
        self.sizer_1.Add(self.viewbutton, 0, wx.ALL|wx.EXPAND, 5)
        
        bmpclose = wx.Bitmap("%s/close_16.png" % resources, wx.BITMAP_TYPE_PNG)
        self.closebutton = bbutton(self, bitmap=bmpclose, style=wx.BU_LEFT,
                                  label='  Close')
        self.sizer_1.Add(self.closebutton, 0, wx.ALIGN_RIGHT|wx.ALL, 5)        
        
        #bitmap menus        
        self.desktopmenu = wx.MenuItem(self.filemenu, ID_DESKTOP, "New desktop screenshot\t%s" % self.options.kb_desktop.GetValue())
        self.desktopmenu.SetBitmap(wx.Bitmap("%s/desktop_16.png" % resources, wx.BITMAP_TYPE_PNG))
        self.filemenu.AppendItem(self.desktopmenu)
        
        self.windowmenu = wx.MenuItem(self.filemenu, ID_WINDOW, "New active window screenshot\t%s" % self.options.kb_window.GetValue())
        self.windowmenu.SetBitmap(wx.Bitmap("%s/window_16.png" % resources, wx.BITMAP_TYPE_PNG))
        self.filemenu.AppendItem(self.windowmenu)
        
        self.regionmenu = wx.MenuItem(self.filemenu, ID_REGION, "New region screenshot\t%s" % self.options.kb_region.GetValue())
        self.regionmenu.SetBitmap(wx.Bitmap("%s/region_16.png" % resources, wx.BITMAP_TYPE_PNG))
        self.filemenu.AppendItem(self.regionmenu)
        
        self.filemenu.AppendSeparator()
        
        self.viewmenu = wx.MenuItem(self.filemenu, ID_VIEW, 'View\tCtrl+V')
        self.viewmenu.SetBitmap(wx.Bitmap("%s/view_16.png" % resources, wx.BITMAP_TYPE_PNG))
        self.filemenu.AppendItem(self.viewmenu)
        
        self.savemenu = wx.MenuItem(self.filemenu, ID_SAVE, 'Save as\tCtrl+S')
        self.savemenu.SetBitmap(wx.Bitmap("%s/save_16.png" % resources, wx.BITMAP_TYPE_PNG))
        self.filemenu.AppendItem(self.savemenu)
        
        self.filemenu.AppendSeparator()
        
        self.quitmenu = wx.MenuItem(self.filemenu, ID_QUIT, 'Quit\tCtrl+Q')
        self.quitmenu.SetBitmap(wx.Bitmap("%s/quit_16.png" % resources, wx.BITMAP_TYPE_PNG))
       	self.filemenu.AppendItem(self.quitmenu)
        
        self.copymenu = wx.MenuItem(self.editmenu, ID_COPY, 'Copy\tCtrl+C')
        self.copymenu.SetBitmap(wx.Bitmap("%s/copy_16.png" % resources, wx.BITMAP_TYPE_PNG))
        self.editmenu.AppendItem(self.copymenu)
        self.editmenu.AppendSeparator()
        self.prefmenu = wx.MenuItem(self.editmenu, ID_PREFS, 'Preferences\tCtrl+R')
        self.prefmenu.SetBitmap(wx.Bitmap("%s/settings_16.png" % resources, wx.BITMAP_TYPE_PNG))
        self.editmenu.AppendItem(self.prefmenu)
        
        #edit tools
        self.drawingtoolsbuttons = []
        self.drawcolorbutton = wx.ColourPickerCtrl(self.drawpanel, -1)
        self.drawcolorbutton.SetToolTipString('Pen color')
        self.grid_sizer_2.Add(self.drawcolorbutton)
        bmprect = wx.Bitmap("%s/rectangle_16.png" % resources, wx.BITMAP_TYPE_PNG)
        self.drawrectbutton = tbutton(self.drawpanel, ID_DRAW_RECT, bitmap=bmprect)
        self.grid_sizer_2.Add(self.drawrectbutton)
        self.drawingtoolsbuttons.append(self.drawrectbutton)
        bmpcircle = wx.Bitmap("%s/circle_16.png" % resources, wx.BITMAP_TYPE_PNG)
        self.drawcirclebutton = tbutton(self.drawpanel, ID_DRAW_CIRCLE, bitmap=bmpcircle)
        self.grid_sizer_2.Add(self.drawcirclebutton)
        self.drawingtoolsbuttons.append(self.drawcirclebutton)
        bmpfree = wx.Bitmap("%s/freeform_16.png" % resources, wx.BITMAP_TYPE_PNG)
        self.drawfreebutton = tbutton(self.drawpanel, ID_DRAW_FREE, bitmap=bmpfree)
        self.grid_sizer_2.Add(self.drawfreebutton)
        self.drawingtoolsbuttons.append(self.drawfreebutton)
        bmpline = wx.Bitmap("%s/line_16.png" % resources, wx.BITMAP_TYPE_PNG)
        self.drawlinebutton = tbutton(self.drawpanel, ID_DRAW_LINE, bitmap=bmpline)
        self.grid_sizer_2.Add(self.drawlinebutton)
        self.drawingtoolsbuttons.append(self.drawlinebutton)
        self.drawlinesizebutton = intbutton.IntButton(self.drawpanel)
        self.drawlinesizebutton.SetToolTipString('Pen thickness in pixels. Left click or wheel up to increase, \
right click or wheel down to decrease.')
        self.grid_sizer_2.Add(self.drawlinesizebutton)
        bmparrow = wx.Bitmap("%s/arrow_16.png" % resources, wx.BITMAP_TYPE_PNG)
        self.drawarrowbutton = tbutton(self.drawpanel, ID_DRAW_ARROW, bitmap=bmparrow)
        self.grid_sizer_2.Add(self.drawarrowbutton)
        self.drawingtoolsbuttons.append(self.drawarrowbutton)
        bmpblur = wx.Bitmap("%s/blur_16.png" % resources, wx.BITMAP_TYPE_PNG)
        self.drawblurbutton = tbutton(self.drawpanel, ID_DRAW_BLUR, bitmap=bmpblur)
        self.grid_sizer_2.Add(self.drawblurbutton)
        self.drawingtoolsbuttons.append(self.drawblurbutton)
        bmpclear = wx.Bitmap("%s/clear_16.png" % resources, wx.BITMAP_TYPE_PNG)
        self.drawclearbutton = tbutton(self.drawpanel, ID_DRAW_CLEAR, bitmap=bmpclear)
        self.grid_sizer_2.Add(self.drawclearbutton)
        self.drawingtoolsbuttons.append(self.drawclearbutton)
        (w, h) = self.drawrectbutton.GetClientSizeTuple()
        self.drawcolorbutton.SetSizeHints(w, h)
        self.drawlinesizebutton.SetSizeHints(w, h)
        self.drawpanel.Enable(False)
        
    def __set_properties(self):
        # begin wxGlade: QSSFrame.__set_properties
        self.SetTitle("QuickScreenShots")
        self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))
        self.previewBitmap.SetBackgroundColour(wx.Colour(255, 255, 255))
        self.panel_1.SetMinSize((500, 400))
        self.panel_1.SetBackgroundColour(wx.Colour(255, 255, 255))
        self.savesettingsbutton.SetSize(self.savesettingsbutton.GetBestSize())
        self.shadowsettingsbutton.SetSize(self.shadowsettingsbutton.GetBestSize())
        self.rotatesettingsbutton.SetSize(self.rotatesettingsbutton.GetBestSize())
        self.label_1.SetForegroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DSHADOW))
        # end wxGlade
        if not self.panel_1.IsDoubleBuffered():
            self.panel_1.SetDoubleBuffered(True)

    def __do_layout(self):
        # begin wxGlade: QSSFrame.__do_layout
        sizer_2 = wx.BoxSizer(wx.VERTICAL)
        sizer_1 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_3 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_4 = wx.BoxSizer(wx.VERTICAL)
        sizer_5 = wx.BoxSizer(wx.VERTICAL)
        grid_sizer_2 = wx.GridSizer(2, 5, 0, 0)
        grid_sizer_1 = wx.GridSizer(5, 2, 0, 2)
        sizer_6 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_6.Add(self.previewBitmap, 2, wx.ALL|wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL, 5)
        self.panel_1.SetSizer(sizer_6)
        sizer_3.Add(self.panel_1, 1, wx.ALL|wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL, 5)
        sizer_4.Add((20, 30), 0, wx.EXPAND, 0)
        grid_sizer_1.Add(self.copycheckbox, 0, wx.EXPAND, 0)
        grid_sizer_1.Add((20, 20), 0, 0, 0)
        grid_sizer_1.Add(self.savecheckbox, 0, wx.EXPAND, 0)
        grid_sizer_1.Add(self.savesettingsbutton, 0, wx.ALIGN_RIGHT, 0)
        grid_sizer_1.Add(self.shadowcheckbox, 0, wx.EXPAND, 0)
        grid_sizer_1.Add(self.shadowsettingsbutton, 0, wx.ALIGN_RIGHT, 0)
        grid_sizer_1.Add(self.rotatecheckbox, 0, wx.EXPAND, 0)
        grid_sizer_1.Add(self.rotatesettingsbutton, 0, wx.ALIGN_RIGHT, 0)
        grid_sizer_1.Add(self.monocheckbox, 0, wx.EXPAND, 0)
        grid_sizer_1.Add((20, 20), 0, 0, 0)
        sizer_4.Add(grid_sizer_1, 1, wx.ALL|wx.EXPAND, 8)
        sizer_4.Add((20, 10), 0, wx.EXPAND, 0)
        sizer_5.Add(self.label_1, 0, wx.BOTTOM|wx.ALIGN_CENTER_HORIZONTAL, 5)
        self.drawpanel.SetSizer(grid_sizer_2)
        sizer_5.Add(self.drawpanel, 0, wx.ALIGN_CENTER_HORIZONTAL, 0)
        sizer_4.Add(sizer_5, 1, wx.EXPAND, 0)
        sizer_3.Add(sizer_4, 0, 0, 0)
        sizer_2.Add(sizer_3, 1, wx.EXPAND, 0)
        sizer_2.Add(sizer_1, 0, wx.EXPAND, 0)
        self.SetSizer(sizer_2)
        sizer_2.Fit(self)
        sizer_2.SetSizeHints(self)
        self.Layout()
        # end wxGlade
        self.sizer_4 = sizer_4
        self.sizer_1 = sizer_1
        self.grid_sizer_2 = grid_sizer_2
        self.sizer_6 = sizer_6
        self.sizer_3 = sizer_3
        
    def OnMouseEvent(self, event):
        """
        Shamelessly copied from wxpython pySketch sample, written by Erik Westra and Bill Baxter.
        """
        
        def getEventCoordinates(event):
            originX, originY = self.scrolled.GetViewStart()
            unitX, unitY = self.scrolled.GetScrollPixelsPerUnit()
            return wx.Point(event.GetX() + (originX * unitX),
                           event.GetY() + (originY * unitY))
        
        if self.curTool is None: return
        
        #prevent the scrolled window doublebuffering from buffering the actual drawing
        #or else, the drawing doesn't appear to be done while dragging a drawing tool
        if event.LeftDown():
            self.scrolled.SetDoubleBuffered(False)

        # Translate event into canvas coordinates and pass to current tool
        origx,origy = event.X, event.Y
        pt = getEventCoordinates(event)
        event.m_x = pt.x
        event.m_y = pt.y
        handled = self.curTool.onMouseEvent(self,event)
        event.m_x = origx
        event.m_y = origy

    def onPaint(self, event):
        event.Skip()
        if self.drawing_mode:
            # force the bitmap to be in the upper left corner of the scrolled window
            self.previewBitmap.SetClientSize(self.previewBitmap.GetBestSize())
    
    def OnResize(self, event):
        """Update the screenshot preview only if the user is not currently
        resizing the window"""
        self.Layout()
        if not self.resizing:
            self.UpdateThumbnail()
    
    def OnResizing(self, event):
        """When the window is being resized, remove the screenshot preview
        to make the process smoother"""
        self.resizing = True
        self.previewBitmap.SetBitmap(wx.NullBitmap)
        event.Skip()   
        
    def OnTimer(self, event):
        """Every so many seconds, check if the user is done resizing the window
        If so, finally update the screenshot preview"""
        self.currentsize = self.GetSize()
        if self.resizing:
            if self.previoussize != self.currentsize:
                self.previoussize = self.currentsize
            else:
                self.resizing = False
                self.UpdateThumbnail()
                 
    def OnCheckbox(self, event):
        status = event.GetEventObject().GetValue()
        evt_obj = None
        if event.GetEventObject() == self.copycheckbox:
            self.options.copy_use.SetValue(status)
        if event.GetEventObject() == self.savecheckbox:
            self.options.save_use.SetValue(status)
        if event.GetEventObject() == self.shadowcheckbox or \
           event.GetEventObject() == self.rotatecheckbox or \
           event.GetEventObject() == self.monocheckbox:
            self.options.shadow_use.SetValue(self.shadowcheckbox.GetValue())
            self.options.rotate_use.SetValue(self.rotatecheckbox.GetValue())
            self.options.mono_use.SetValue(self.monocheckbox.GetValue())
            evt_obj = EffectEvent(self.im, None, ID_REAPPLY)
        if evt_obj:
            self.evthdl.ProcessEvent(evt_obj)
            
    def OnClose(self, event):
        """Don't close, just hide the window"""
        self.Show(False)

    def onButton(self, event):
        evt_obj = None
        if event.GetEventObject() in self.drawingtoolsbuttons:
            self.OnDrawingToolButton(event)
        if event.GetEventObject() == self.regionbutton:
            evt_obj = ScreenshotEvent(ID_REGION)
        if event.GetEventObject() == self.windowbutton:
            evt_obj = ScreenshotEvent(ID_WINDOW)
        if event.GetEventObject() == self.desktopbutton:
            evt_obj = ScreenshotEvent(ID_DESKTOP)
        if event.GetEventObject() == self.copybutton:
            evt_obj = CommandEvent(self.im, None, ID_COPY)
        if event.GetEventObject() == self.viewbutton:
            evt_obj = CommandEvent(self.im, None, ID_VIEW)
        if event.GetEventObject() == self.closebutton:
            evt_obj = CommandEvent(None, None, ID_CLOSE)
        if event.GetEventObject() == self.savebutton:
            self.save()
        if event.GetEventObject() == self.savesettingsbutton:
            evt_obj = CommandEvent(None, 'save', ID_PREFS)
        if event.GetEventObject() == self.shadowsettingsbutton:
            evt_obj = CommandEvent(None, 'shadow', ID_PREFS)
        if event.GetEventObject() == self.rotatesettingsbutton:
            evt_obj = CommandEvent(None, 'rotate', ID_PREFS)
        if evt_obj:
            self.evthdl.ProcessEvent(evt_obj)
        return False
        
    def OnDesktopHotkey(self, event):
        evt_obj = ScreenshotEvent(ID_DESKTOP)
        self.evthdl.ProcessEvent(evt_obj)
        
    def OnWindowHotkey(self, event):
        evt_obj = ScreenshotEvent(ID_WINDOW)
        self.evthdl.ProcessEvent(evt_obj)
        
    def OnRegionHotkey(self, event):
        evt_obj = ScreenshotEvent(ID_REGION)
        self.evthdl.ProcessEvent(evt_obj)
        
    def OnColorChanged(self, event):
        if event.GetEventObject() == self.drawcolorbutton:
            col = self.drawcolorbutton.GetColour().GetAsString(wx.C2S_HTML_SYNTAX)
            self.options.draw_line_color.SetValue(col)
            self.penColour = self.drawcolorbutton.GetColour()
    
    def OnSpinButtonChanged(self, event):
        v = event.GetValue()
        self.options.draw_line_size.SetValue(v)
        self.lineSize = v
        
    def OnDrawingToolButton(self, event):
        button = event.GetEventObject()
        pressed = button.GetValue()
        event_type = None
        
        if pressed:
        
            """Unpress other buttons"""
            for b in self.drawingtoolsbuttons:
                if b != button:
                    b.SetValue(False)
                    
            """Assign current drawing tool"""
            if button == self.drawrectbutton:
                self.curTool = self.recttool
            elif button == self.drawcirclebutton:
                self.curTool = self.circletool
            elif button == self.drawfreebutton:
                self.curTool = self.freetool
            elif button == self.drawlinebutton:
                self.curTool = self.linetool
            elif button == self.drawarrowbutton:
                self.curTool = self.arrowtool
            elif button == self.drawblurbutton:
                self.curTool = self.blurtool
            elif button == self.drawclearbutton:
                """Replace screenshot with original and trigger
                   re-applying effects"""
                self.SetIM(self.orig_im)
                evt_obj = EffectEvent(self.im, None, ID_REAPPLY)
                self.evthdl.ProcessEvent(evt_obj)
                """Un push and disable the button"""
                self.drawclearbutton.SetValue(False)
                self.drawclearbutton.Enable(False)
                """Don't return to drawing mode if were not in it"""
                if not self.drawing_mode:
                    return
            else:
                self.curTool = None
            
        else:
            self.curTool = None
        
        """Assign drawing area cursor"""
        if self.curTool:
            self.scrolled.SetCursor(self.curTool.getDefaultCursor())
        else:
            self.scrolled.SetCursor(wx.STANDARD_CURSOR)
                
        self.SetDrawingMode(not self.drawing_mode)

    def onMenu(self, event): # wxGlade: QSSFrame.<event_handler>
        evt_obj = None
        if event.GetId() == ID_REGION:
            evt_obj = ScreenshotEvent(ID_REGION)
        if event.GetId() == ID_WINDOW:
            evt_obj = ScreenshotEvent(ID_WINDOW)
        if event.GetId() == ID_DESKTOP:
            evt_obj = ScreenshotEvent(ID_DESKTOP)
        if event.GetId() == ID_COPY:
            evt_obj = CommandEvent(None, None, ID_COPY)
        if event.GetId() == ID_UPDATE:
            evt_obj = CommandEvent(None, None, ID_UPDATE)
        if event.GetId() == ID_VIEW:
            evt_obj = CommandEvent(self.im, None, ID_VIEW)
        if event.GetId() == ID_QUIT:
            evt_obj = CommandEvent(None, None, ID_QUIT)
        if event.GetId() == ID_PRINT:
            self.doprint()
        if event.GetId() == ID_SAVE:
            self.save()
        if event.GetId() == ID_ABOUT:
            self.about()
        if event.GetId() == ID_HOMEPAGE:
            self.homepage()
        if event.GetId() == ID_PREFS:
            evt_obj = CommandEvent(None, 'general', ID_PREFS)
        if evt_obj:
            self.evthdl.ProcessEvent(evt_obj)
        return False

# end of class QSSFrame


if __name__ == "__main__":
    def onScreenshot(event):
        if event.GetId() == ID_REGION:
            print "region screenshot!"
        if event.GetId() == ID_DESKTOP:
            print "desktop screenshot!"
        if event.GetId() == ID_WINDOW:
            print "window screenshot!"
    def onCommand(event):
        if event.GetId() == ID_COPY:
            print "copy!"
        if event.GetId() == ID_CLOSE:
            print "close!"
        if event.GetId() == ID_VIEW:
            print "view!"
        if event.GetId() == ID_QUIT:
            app.Exit()
        if event.GetId() == ID_SAVE:
            print "Save! ->", event.GetParams()
        if event.GetId() == ID_PREFS:
            print "Prefs! ->", event.GetParams()
    def onEffectEvent(event):
        if event.GetId() == ID_SHADOW:
            print "shadow! ->", event.GetParams()
        if event.GetId() == ID_ROTATE:
            print "rotate! ->", event.GetParams()
            
    opts = options.load()
    app = wx.PySimpleApp(0)
    wx.InitAllImageHandlers()
    frame_2 = QSSFrame(opts, app, None, -1, "")
    app.SetTopWindow(frame_2)
    app.Bind(EVT_SCREENSHOT_EVENT, onScreenshot)
    app.Bind(EVT_COMMAND_EVENT, onCommand)
    app.Bind(EVT_EFFECT_EVENT, onEffectEvent)
    frame_2.Show()
    app.MainLoop()
    